package com.xtaller.lazy.api.common;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wf.captcha.Captcha;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.utils.CaptchaUtil;
import com.xtaller.lazy.Cache;
import com.xtaller.lazy.TableGenerator;
import com.xtaller.lazy.anync.JwtTask;
import com.xtaller.lazy.anync.LoginTask;
import com.xtaller.lazy.base.TApi;
import com.xtaller.lazy.lib.R;
import com.xtaller.lazy.lib.annotation.Token;
import com.xtaller.lazy.lib.convert.*;
import com.xtaller.lazy.lib.kit.*;
import com.xtaller.lazy.model.base.Statistics;
import com.xtaller.lazy.model.base.User;
import com.xtaller.lazy.model.base.UserRole;
import com.xtaller.lazy.model.system.*;
import com.xtaller.lazy.parameter.DocGenerate;
import com.xtaller.lazy.parameter.DocLogin;
import com.xtaller.lazy.service.base.DepartmentService;
import com.xtaller.lazy.service.base.StatisticsService;
import com.xtaller.lazy.service.base.UserRoleService;
import com.xtaller.lazy.service.base.UserService;
import com.xtaller.lazy.service.system.AuthoritiesService;
import com.xtaller.lazy.service.system.DictService;
import com.xtaller.lazy.service.system.GenerateCodeService;
import com.xtaller.lazy.service.system.RoleAuthService;
import com.xtaller.lazy.util.CacheUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @version V1.0
 * @author: Taller
 * @date: 2019-04-02
 * @Description: 基础api
 */
@Api(tags = "基础api")
@RestController
@RequestMapping("/v1/common")
public class BaseApi extends TApi {
    @Autowired private UserService userService;
    @Autowired private JwtTask jwtTask;
    @Autowired private UserRoleService userRoleService;
    @Autowired private AuthoritiesService authoritiesService;
    @Autowired private RoleAuthService roleAuthService;
    @Autowired private GenerateCodeService codeService;
    @Autowired private DepartmentService departmentService;
    @Autowired private StatisticsService statisticsService;
    @Autowired private CacheUtil cacheUtil;
    @Autowired private LoginTask loginTask;
    @Autowired private DictService dictService;


    private Map<String, String> LoginVerify() {
        var verify = M.create("loginName", "登录账号不能为空")
                        .put("password", "登录密码不能为空");
        return verify;
    }

    @PostMapping("/login/{platform}")
    @ApiOperation("基本登录")
    public Object login(@ApiParam("登录对象") @RequestBody DocLogin object, @ApiParam("平台编号") @PathVariable(required = true) int platform){
        var check = V.checkEmpty(LoginVerify(), object);
        if (check.getBoolean(CHECK)) {
            return R.error(check.getString("message"));
        }
        // 验证码校验
        switch (platform){
            case 1:
                if(V.isEmpty(object.getCode())){
                    return R.error("请输入验证码");
                }
                var key = subject.get().get("key").toString();
                if(!V.isEqual(key, object.getCode())){
                    return R.error("验证码有误");
                }
                break;
            default:
                break;
        }

        var qw = new QueryWrapper<User>();
        qw.lambda().eq(User::getLoginName, object.getLoginName());
        var user = userService.getOne(qw);

        if(user == null) {
            return R.error("用户名或者密码错误 code 1001");
        }
        if(user.getState() == 1) {
            return R.error("当前用户已经被冻结 code 1003");
        }
        if (!checkPwd(user, object.getPassword())) {
            return R.error("用户名或者密码错误 code 1002");
        }
        var result = formatData(user, 1);

        return R.ok(result);
    }

    @GetMapping("/token/{platform}")
    @ApiOperation("通过token登录")
    @Token
    public Object token(@ApiParam("平台编号") @PathVariable("platform") int platform){
        var uid = userId.get();
        if(uid == 0L) {
            return R.error("登录状态已经失效");
        }
        var user = userService.getById(uid);
        if(user == null) {
            return R.error("用户数据异常");
        }
        var result = formatData(user, platform);
        return R.ok(result);
    }

    @GetMapping("/vimg")
    @ApiOperation("生成图形验证码")
    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 设置请求头为输出图片类型
        CaptchaUtil.setHeader(response);
        // 三个参数分别为宽、高、位数
        GifCaptcha gifCaptcha = new GifCaptcha(130, 48, 5);
        // 设置字体
        gifCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32));
        // 设置类型，纯数字、纯字母、字母数字混合
        gifCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
        var jwt = JwtUtil.createJWT(0L, M.create("key", gifCaptcha.text().toLowerCase()), 180 * 1000);
        response.setHeader("token", jwt);
        // 输出图片流
        gifCaptcha.out(response.getOutputStream());
    }

    @GetMapping("/img")
    @ApiOperation("生成base64图片")
    public Object getImgUrlToBase64() {
        var imgUrl = paramStr.apply("url");
        return R.ok(ImgUtil.urlImg2Base64(imgUrl));
    }

    @GetMapping("/auth")
    @ApiOperation("获取用户权限信息")
    @Token
    public Object auth(){
        return R.ok(getAuthByUserId(userId.get()));
    }

    @GetMapping("/exit")
    @ApiOperation("退出登录")
    @Token
    public Object exit(){
        var uid = userId.get();
        if(uid != 0L){
            var item = subject.get().get("platform");
            var key = S.apppend(item, "-", uid);
            cacheUtil.set(key, J.create());
        }
        return R.ok("退出系统成功");
    }

    /**
     * 密码校验
     * */
    private boolean checkPwd(User user, String userPwd) {
        // 判断密码正确性
        var oldPwd = user.getPassword();
        var salt = user.getSalt();
        var checkPwd = MD5Util.encode(S.apppend(userPwd, salt));
        if (V.isEqual(oldPwd, checkPwd)) {
            return true;
        }
        return false;
    }
    /**
     * 生成JWT认证数据
     * */
    private String createJwt(User user, int platform) {
        return JwtUtil.createJWT(
                user.getId(),
                M.create("userId", user.getId()).put("time", TimeUtil.getTimestamp()).put("platform", platform),
                0);
    }
    /**
     * 用户数据处理
     * */
    private JSONObject formatData(User user, int platform) {
        var auth = new JSONObject();
        auth.put("user", formatUser(user));
        // 1管理用户 2CMS用户 3Shop用户
        String token = createJwt(user, platform);
        auth.put("token", token);
        // 写入登录日志
        var log = new LoginLog();
        log.setIp(request.getRemoteAddr());
        log.setUserId(user.getId());
        log.setPlatform(platform);
        log.setCreateId(user.getId());
        log.setLoginName(user.getLoginName());
        loginTask.setLog(log);
        // 写入缓存jwt
        jwtTask.updateJwt(user.getId(), platform, token);
        return auth;
    }
    /**
     * 读取当前用户角色权限
     * */
    private Object getAuthByUserId(Long userId){
        var permissionList = new ArrayList<String>();
        var auths = J.list();

        var urQw = new QueryWrapper<UserRole>();
        urQw.lambda().eq(UserRole::getUserId, userId);
        var roles = userRoleService.list(urQw);

        if(roles.size() > 0){
            var roleIds = roles.stream()
                    .map(m -> m.getRoleId())
                    .distinct()
                    .collect(Collectors.toList());
            var raQw = new QueryWrapper<RoleAuth>();
            raQw.lambda().in(RoleAuth::getRoleId, roleIds);
            var ras = roleAuthService.list(raQw);
            var authIds = ras.stream()
                    .map(m -> m.getAuthId())
                    .distinct()
                    .collect(Collectors.toList());

            if(authIds.size() > 0){
                var authorities = authoritiesService.listByIds(authIds);
                authorities.stream().sorted((y, x) -> x.getOrderNumber() - y.getOrderNumber());
                // 处理子项数据
                var parents = getAuthByParentId(authorities, 0L, 0);

                var obj = J.o2l(parents);
                obj.stream().forEach(o -> {
                    var sub = getAuthByParentId(authorities, o.getLong("id"), 0);
                    var subs = J.o2l(sub);
                    if(sub.size() > 0){
                        for(var s: subs){
                            var permission = getAuthByParentId(authorities, s.getLong("id"), 1);
                            Collections.sort(permission, new AuthoritiesTypeComparetor());
                            s.put("name", s.get("name"));
                            s.put("path", s.get("path"));
                            s.put("url", s.get("url"));
                            s.put("icon", s.get("icon"));
                            s.put("permission", permission);
                            if(permission.size() > 0){
                                var per = J.list();
                                for(var ps:permission){
                                    var p = J.create("name", ps.getName())
                                            .put("event", ps.getEvent())
                                            .put("color", ps.getColor())
                                            .put("type", ps.getType());
                                    permissionList.add(ps.getFlag());
                                    per.add(p);
                                }
                                s.put("permission", per);
                            }

                        }
                    }
                    o.put("name", o.get("name"));
                    o.put("path", o.get("path"));
                    o.put("url", o.get("url"));
                    o.put("icon", o.get("icon"));
                    o.put("sub", subs);
                    auths.add(o);
                });
            }
        }
        var key = S.apppend("user-auth-", userId);
        cacheUtil.set(key, permissionList);
//        Cache.set(
//                S.apppend("user-", userId),
//                permissionList,
//                0);
        return auths;
    }

    @PostMapping("/generate")
    @ApiOperation("代码生成")
    @Token
    public Object generate(@ApiParam("数据对象") @RequestBody DocGenerate object){
        try {
            new TableGenerator().run(object.getTableName(), object.getModule());
            var model = J.o2m(object, GenerateCode.class);
            codeService.save(model);
            return R.ok("生成成功");
        } catch (SQLException e) {
            e.printStackTrace();
            return R.error("生成失败");
        } catch (IOException e) {
            e.printStackTrace();
            return R.error("生成失败");
        }
    }

    @GetMapping("/generate")
    @ApiOperation("读取代码生成记录")
    @Token
    public Object table(@ApiParam("页码") @RequestParam(value = "page", required = false, defaultValue = "1") int page,
                        @ApiParam("页长") @RequestParam(value = "limit", required = false, defaultValue = "50") int limit){
        var p = new Page<GenerateCode>(page, limit);
        var qw = new QueryWrapper<GenerateCode>();
        qw.lambda().orderByDesc(GenerateCode::getCreateTime);
        return p2t(codeService.page(p, qw));
    }

    @GetMapping("/tree")
    public Object tree(){
        var trees = departmentService.list();
        return L.list2Tree(trees, 0L);
    }

    @GetMapping("/statistics/{type}")
    @ApiOperation("获取统计访问量")
    public Object getStatistics(@PathVariable() int type){
        var qw = new QueryWrapper<Statistics>();
        qw.lambda().eq(Statistics::getType, type);
        var statistics = statisticsService.getOne(qw);
        if(statistics == null){
            return R.ok(J.create("count", 1));
        }
        return R.ok(J.create("count", statistics.getCount() + 1));
    }

    @PostMapping("/statistics/{type}")
    @ApiOperation("统计访问量+1")
    public Object setStatistics(@PathVariable() int type){
        var qw = new QueryWrapper<Statistics>();
        qw.eq("type", type);
        var statistics = statisticsService.getOne(qw);
        if(statistics == null){
            statistics = new Statistics();
            statistics.setCount(1);
            statistics.setType(type);
            statisticsService.save(statistics);
            return R.ok(J.create("count", 1));
        }
        statistics.setCount(statistics.getCount() + 1);
        statisticsService.updateById(statistics);
        return R.ok(J.create("count", statistics.getCount()));
    }

    @GetMapping("/dict/{code}")
    @Token
    public Object getDictByCode(@PathVariable() String code){
        var qw = new QueryWrapper<Dict>();
        qw.lambda().eq(Dict::getCode, code);
        var dict = dictService.getOne(qw);
        if(dict == null){
            return R.ok("", J.list());
        }
        var parentId = dict.getParentId();
        var id = dict.getId();
        qw = new QueryWrapper<Dict>();
        qw.lambda().or(x -> x.eq(Dict::getParentId, parentId)
                        .or().eq(Dict::getCode, code));
        var dicts = dictService.list(qw);
        return R.ok(L.list2Tree(formatDict(dicts), id));
    }
}
